Skip to content

feat(buzz-acp): isolate sessions by conversation thread - #2331

Open
bbamnesia wants to merge 1 commit into
block:mainfrom
bbamnesia:feat/thread-scoped-acp-sessions
Open

feat(buzz-acp): isolate sessions by conversation thread#2331
bbamnesia wants to merge 1 commit into
block:mainfrom
bbamnesia:feat/thread-scoped-acp-sessions

Conversation

@bbamnesia

Copy link
Copy Markdown

Summary

Give each Buzz conversation thread its own ACP session while preserving channel-level behavior for unthreaded messages and DMs.

  • derive a typed conversation scope from the channel and canonical NIP-10 root
  • scope forum roots by their own event ID so forum posts and comments share one session
  • key queueing, in-flight work, cancellation, rotation, and session state by conversation scope
  • allow sibling threads in one channel to execute concurrently without batching or steering each other
  • keep session ownership sticky to one agent while history exists, including when that agent is busy
  • apply desktop model changes across every scoped session in a channel without leaking models to unrelated channels
  • resolve metadata before subscribing to dynamically joined channels so the first event cannot be routed under the wrong scope
  • keep DMs channel-scoped

Behavior

  • replies in one thread reuse one ACP session
  • separate threads in the same channel use separate ACP sessions
  • separate forum posts use separate ACP sessions
  • top-level unthreaded messages retain channel-level continuity
  • !cancel, !rotate, queue deduplication, and retry state target the current conversation scope
  • channel removal still drains all scopes under that channel

Tests

  • cargo test -p buzz-acp605 passed
  • cargo fmt -p buzz-acp -- --check — passed
  • cargo clippy -p buzz-acp --all-targets -- -D warnings — passed
  • cargo check -p sprig — passed
  • workspace Rust fmt/clippy — passed
  • desktop TypeScript/Biome/policy checks — passed
  • desktop Tauri fmt/clippy — passed
  • web checks — passed

just ci reaches the workspace unit suite but current main has an unrelated deterministic buzz-db failure in replica_fence::tests::fence_starts_closed_and_opens_on_advance: the assertion compares a microsecond-truncated stored timestamp with its original nanosecond value. The same isolated test fails without involving any files changed here.

@bbamnesia
bbamnesia requested a review from a team as a code owner July 22, 2026 05:17
@bbamnesia
bbamnesia force-pushed the feat/thread-scoped-acp-sessions branch from 445556b to 68345bc Compare July 22, 2026 05:17
@skyerus

skyerus commented Jul 27, 2026

Copy link
Copy Markdown

We are hitting the exact failure mode this PR addresses in real team use on a current Buzz Desktop build.

Sanitized repro:

  1. A managed coding agent is configured with parallelism=24.
  2. Two unrelated top-level bug threads in the same channel mention that agent while the first turn is still active.
  3. The harness startup state is agents=24 ... dedup=Queue meh=Steer.
  4. For the later root, native steer reports ExpectedRunIdMissing and falls back to channel-scoped cancel-and-merge.
  5. The agent completes the later bug but leaves the earlier bug without a result or blocker; when prompted later, it explicitly reports that the first investigation was displaced by the subsequent assignment.

We reproduced the same outcome with two independent bug roots sent nine seconds apart: only the second was picked up and shipped. The other 23 configured workers could not help because the in-flight boundary was the channel rather than the canonical root.

This makes thread scoping a correctness and throughput issue, not only a context-window improvement. A bug/intake channel naturally uses one top-level thread per independent task; users reasonably expect those roots to claim separate workers while replies within each root remain serialized and context-continuous.

The behavior proposed here—queue, cancellation, rotation, and session state keyed by conversation scope, with sibling roots executing concurrently—is exactly the contract we need. We would be happy to test a rebased version with a controlled three-root burst and verify:

  • all three roots start on separate workers;
  • each produces one thread-local callback;
  • no prompt context crosses roots;
  • no source ID or side effect is duplicated.

At present the operational choices are either serial assignment in the intake channel or splitting work into extra channels, both of which underuse the configured pool and undermine the thread model. A rebase/review of this PR would remove that workaround.

@bbamnesia
bbamnesia force-pushed the feat/thread-scoped-acp-sessions branch from 68345bc to ad91e04 Compare July 28, 2026 23:45
@bbamnesia

Copy link
Copy Markdown
Author

@skyerus The branch is now rebased onto current main (90e058eb) and updated at ad91e042.

The repair now uses one canonical NIP-10 parser across relay ingestion and ACP scoping, keys queue/in-flight/session ownership and invalidation by conversation scope, prevents cross-root context hydration, closes active/idle/future model-switch lifecycle holes, and carries thread-root identity through observer telemetry/UI correlation.

I also added a real-subprocess acceptance test for the burst you described: three simultaneous forum roots claim three fake ACP workers; same-root replies remain serialized to one owner/session; five source events produce exactly one prompt, callback, and terminal frame each; reactions/cleanup happen once; and no context crosses roots.

Would you be willing to run your controlled three-root burst against this head and report what you see?

Local verification on the final rebased commit:

  • cargo test -p buzz-acp --locked: 687 passed, plus 9 lifecycle tests
  • canonical thread parser: 6 passed
  • desktop typecheck/check and focused observer/model tests: 119 passed
  • workspace formatting/clippy, Sprig check, desktop/web/mobile checks: passed
  • full just ci reaches unit tests and stops only on the unchanged buzz-db timestamp-precision assertion (replica_fence::tests::fence_starts_closed_and_opens_on_advance), which reproduces on clean origin/main

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants